#include "Semantic.h"


Semantic::Semantic(void)
{
}


Semantic::~Semantic(void)
{
}

void Semantic::eval(ParserTree* tree,  Value& value, AList alist)
{
	if (!tree)
	{
		value.type = NOTHING;
	}
	else if (!tree->isDOT())
	{
		//	reach the leaf
		if (tree->isNumber())
		{
			value.setNumber(tree->getAtom().number);
		}
		else if (tree->isLiteral())
		{
			if (Util::isEqual(tree->getAtom().str, "T") || Util::isEqual(tree->getAtom().str, "NIL"))
			{
				//	reserved words
				value.setLiteral(tree->getAtom().str);
			}
			else
			{
				value = alist.getVariableValue(tree->getAtom().str);
				if (value.type == NOTHING)
				{
					std::cout << "Error: variable evaluation failed at " << tree->getAtom().str.c_str() << "\n";
					exit(1);
				}
			}
		}
	}
	else
	{
		//	evaluate left child and right child
		ParserTree* leftChild = tree->getChild(true);
		if (!leftChild)
		{
			//	no left child, set nil
			value.setNil();
		}
		else if (leftChild->isDOT())
		{
			std::cout << "Error: invalid function name! Function name should be a literal! \n";
			exit(1);
		}
		else if (leftChild->isNumber())
		{
			std::cout << "Error: invalid function name '" << leftChild->getAtom().number << "' !\n";
			exit(1);
		}
		else
		{
			std::string funcName = leftChild->getAtom().str;
			//	reserved functions: CAR, CDR, ATOM, QUOTE, NULL, INT,	PLUS, MINUS, TIMES, QUOTIENT, REMAINDER, EQ, LESS, GREATER,	CONS,  COND,  DEFUN
			if (Util::isEqual(funcName, "CAR"))
				car(tree->getChild(false), value, alist);
			else if (Util::isEqual(funcName, "CDR"))
				cdr(tree->getChild(false), value, alist);
			else if (Util::isEqual(funcName, "ATOM"))
				atom(tree->getChild(false), value, alist);
			else if (Util::isEqual(funcName, "QUOTE"))
				quote(tree->getChild(false), value, alist);
			else if (Util::isEqual(funcName, "NULL"))
				null(tree->getChild(false), value, alist);
			else if (Util::isEqual(funcName, "INT"))
				integer(tree->getChild(false), value, alist);
			else if (Util::isEqual(funcName, "PLUS"))
				arith(tree->getChild(false), value, alist, PLUS);
			else if (Util::isEqual(funcName, "MINUS"))
				arith(tree->getChild(false), value, alist, MINUS);
			else if (Util::isEqual(funcName, "TIMES"))
				arith(tree->getChild(false), value, alist, TIMES);
			else if (Util::isEqual(funcName, "QUOTIENT"))
				arith(tree->getChild(false), value, alist, QUOTIENT);
			else if (Util::isEqual(funcName, "REMAINDER"))
				arith(tree->getChild(false), value, alist, REMAINDER);
			else if (Util::isEqual(funcName, "EQ"))
				arith(tree->getChild(false), value, alist, EQ);
			else if (Util::isEqual(funcName, "LESS"))
				arith(tree->getChild(false), value, alist, LESS);
			else if (Util::isEqual(funcName, "GREATER"))
				arith(tree->getChild(false), value, alist, GREATER);
			else if (Util::isEqual(funcName, "CONS"))
				cons(tree->getChild(false), value, alist);
			else if (Util::isEqual(funcName, "COND"))
				cond(tree->getChild(false), value, alist);
			else if (Util::isEqual(funcName, "DEFUN"))
				defun(tree->getChild(false), value, alist);
			else
			{
				if (dList.findFunction(funcName))
				{
					Value valueList;
					evalList(tree->getChild(false), valueList, alist);
					apply(funcName, value, valueList, alist);
				}
				else
				{
					std::cout << "Error: function '" <<  funcName.c_str() << "' has not defined !\n";
					exit(1);
				}
			}
		}
	}
}

// car result of a list
void Semantic::car(ParserTree* tree, Value& value, AList alist)
{
	if (!tree || !tree->isDOT())
	{
		std::cout << "Error: too few arguments given to CAR !\n";
		exit(1);
	}
	else if (!tree->nilRightChild())
	{
		std::cout << "Error: too many arguments given to CAR !\n";
		exit(1);
	}
	else
	{
		ParserTree* parameter = tree->getChild(true);		//	the real parameter
		Value valuePara;
		eval(parameter, valuePara, alist);
		if (valuePara.isNil())
		{
			value.setNil();									//	(car nil) = nil
		}
		else if (valuePara.type == LIST_VALUE)
		{
			if (valuePara.list->getChild(true)->isDOT())
			{
				value.setList(valuePara.list->getChild(true)->copy());
			}
			else if (valuePara.list->getChild(true)->isLiteral())
			{
				value.setLiteral(valuePara.list->getChild(true)->getAtom().str);
			}
			else if (valuePara.list->getChild(true)->isNumber())
			{
				value.setNumber(valuePara.list->getChild(true)->getAtom().number);
			}
		}
		else
		{
			std::cout << "Error: invalid parameters for CAR !\n";
			exit(1);
		}
	}
}

// cdr result of a list
void Semantic::cdr(ParserTree* tree, Value& value, AList alist)
{
	if (!tree || !tree->isDOT())
	{
		std::cout << "Error: too few arguments given to CDR !\n";
		exit(1);
	}
	else if (!tree->nilRightChild())
	{
		std::cout << "Error: too many arguments given to CDR !\n";
		exit(1);
	}
	else
	{
		ParserTree* parameter = tree->getChild(true);		//	the real parameter
		Value valuePara;
		eval(parameter, valuePara, alist);
		if (valuePara.isNil())
		{
			value.setNil();
		}
		else if (valuePara.type == LIST_VALUE)
		{
			if (!valuePara.list->getChild(false))
			{
				value.setNil();
			}
			else if (valuePara.list->getChild(false)->isDOT())
			{
				value.setList(valuePara.list->getChild(false)->copy());
			}
			else if (valuePara.list->getChild(false)->isLiteral())
			{
				value.setLiteral(valuePara.list->getChild(false)->getAtom().str);
			}
			else if (valuePara.list->getChild(false)->isNumber())
			{
				value.setNumber(valuePara.list->getChild(false)->getAtom().number);
			}
		}
		else
		{
			std::cout << "Error: invalid parameters for CDR !\n";
			exit(1);
		}
	}
}


// check if is atom
void Semantic::atom(ParserTree* tree, Value& value, AList alist)
{
	if (!tree || !tree->isDOT())
	{
		std::cout << "Error: too few arguments given to ATOM !\n";
		exit(1);
	}
	else if (!tree->nilRightChild())
	{
		std::cout << "Error: too many arguments given to ATOM !\n";
		exit(1);
	}
	else
	{
		ParserTree* parameter = tree->getChild(true);		//	the real parameter
		Value valuePara;
		eval(parameter, valuePara, alist);
		if (valuePara.isAtom())
		{
			value.setT();
		}
		else if (valuePara.isList())
		{
			value.setNil();
		}
		else
		{
			std::cout << "Error: invalid parameters for ATOM !\n";
			exit(1);
		}
	}
}

// check if is null
void Semantic::null(ParserTree* tree, Value& value, AList alist)
{
	if (!tree || !tree->isDOT())
	{
		std::cout << "Error: too few arguments given to NULL !\n";
		exit(1);
	}
	else if (!tree->nilRightChild())
	{
		std::cout << "Error: too many arguments given to NULL !\n";
		exit(1);
	}
	else
	{
		ParserTree* parameter = tree->getChild(true);		//	the real parameter
		Value valuePara;
		eval(parameter, valuePara, alist);
		if (valuePara.isNil())
		{
			value.setT();
		}
		else if (valuePara.isAtom() || valuePara.isList())
		{
			value.setNil();
		}
		else
		{
			std::cout << "Error: invalid parameters for NULL !\n";
			exit(1);
		}
	}
}

// check if is int
void Semantic::integer(ParserTree* tree, Value& value, AList alist)
{
	if (!tree || !tree->isDOT())
	{
		std::cout << "Error: too few arguments given to INT !\n";
		exit(1);
	}
	else if (!tree->nilRightChild())
	{
		std::cout << "Error: too many arguments given to INT !\n";
		exit(1);
	}
	else
	{
		ParserTree* parameter = tree->getChild(true);		//	the real parameter
		Value valuePara;
		eval(parameter, valuePara, alist);
		if (valuePara.type == NUMBER_VALUE)
		{
			value.setT();
		}
		else if (valuePara.isAtom() || valuePara.isList())
		{
			value.setNil();
		}
		else
		{
			std::cout << "Error: invalid parameters for INT !\n";
			exit(1);
		}
	}
}

// quote result of a list
void Semantic::quote(ParserTree* tree, Value& value, AList alist)
{
	if (!tree || !tree->isDOT())
	{
		std::cout << "Error: too few arguments given to QUOTE !\n";
		exit(1);
	}
	else if (!tree->nilRightChild())
	{
		std::cout << "Error: too many arguments given to QUOTE !\n";
		exit(1);
	}
	else
	{
		ParserTree* parameter = tree->getChild(true);		//	the real parameter
		if (!parameter)
		{
			std::cout << "Error: invalid parameters for QUOTE !\n";
			exit(1);
		}
		else if (parameter->isDOT())
		{
			if (parameter->getChild(true))
			{
				//	a list
				value.setList(parameter->copy());
			}
			else
			{
				//	NIL or ()
				value.setNil();
			}
		}
		else if (parameter->isLiteral())
		{
			value.setLiteral(parameter->getAtom().str);
		}
		else if (parameter->isNumber())
		{
			value.setNumber(parameter->getAtom().number);
		}
	}
}

// arithmetic, arith: arithmetic operator;
// PLUS, MINUS, TIMES, QUOTIENT, REMAINDER, EQ, LESS, GREATER,
void Semantic::arith(ParserTree* tree, Value& value, AList alist, Arith arith)
{
	std::string arithName;
	switch (arith)
	{
	case PLUS: arithName = "PLUS"; break;
	case MINUS: arithName = "MINUS"; break;
	case TIMES: arithName = "TIMES"; break;
	case QUOTIENT: arithName = "QUOTIENT"; break;
	case REMAINDER: arithName = "REMAINDER"; break;
	case EQ: arithName = "EQ"; break;
	case LESS: arithName = "LESS"; break;
	case GREATER: arithName = "GREATER"; break;
	}

	if (!tree || !tree->isDOT())
	{
		std::cout << "Error: too few arguments given to " << arithName.c_str() << " !\n";
		exit(1);
	}
	else
	{
		ParserTree* parameter1 = tree->getChild(true);				//	parameter 1
		ParserTree* parameter2List = tree->getChild(false);			//	list containing only one element: parameter 2
		if (!parameter2List || !parameter2List->isDOT())
		{
			std::cout << "Error: too few arguments given to " << arithName.c_str() << " !\n";
			exit(1);
		}
		if (!parameter2List->nilRightChild())
		{
			std::cout << "Error: too many arguments given to" << arithName.c_str() << " !\n";
			exit(1);
		}
		ParserTree* parameter2 = parameter2List->getChild(true);	//	parameter 2

		Value valuePara1, valuePara2;
		eval(parameter1, valuePara1, alist);
		eval(parameter2, valuePara2, alist);

		if (valuePara1.isNumber() && valuePara2.isNumber())
		{
			switch (arith)
			{
			case PLUS: value.setNumber(valuePara1.n + valuePara2.n); break;
			case MINUS: value.setNumber(valuePara1.n - valuePara2.n); break;
			case TIMES: value.setNumber(valuePara1.n * valuePara2.n); break;
			case QUOTIENT: value.setNumber(valuePara1.n / valuePara2.n); break;
			case REMAINDER: value.setNumber(valuePara1.n % valuePara2.n); break;
			case EQ:
				if (valuePara1.n == valuePara2.n)
					value.setT();
				else
					value.setNil();
				break;
			case LESS:
				if (valuePara1.n <valuePara2.n)
					value.setT();
				else
					value.setNil();
				break;
			case GREATER:
				if (valuePara1.n > valuePara2.n)
					value.setT();
				else
					value.setNil();
				break;
			}
		}
		else if (arith == EQ)
		{
			if (valuePara1.isLiteral() && valuePara2.isLiteral())
			{
				if (Util::isEqual(valuePara1.str, valuePara2.str))
					value.setT();
				else
					value.setNil();
			}
			else if ((valuePara1.isLiteral() && valuePara2.isNumber()) || (valuePara1.isNumber() && valuePara2.isLiteral()))
			{
				value.setNil();
			}
			else if (valuePara1.isNil() && valuePara2.isNil())
			{
				value.setT();
			}
		}
		else
		{
			std::cout << "Error: invalid operand for " << arithName.c_str() << " !\n";
			exit(1);
		}
	}
}

// cons
void Semantic::cons(ParserTree* tree, Value& value, AList alist)
{
	if (!tree || !tree->isDOT())
	{
		std::cout << "Error: too few arguments given to CONS !\n";
		exit(1);
	}
	else
	{
		ParserTree* parameter1 = tree->getChild(true);				//	parameter 1
		ParserTree* parameter2List = tree->getChild(false);			//	list containing only one element: parameter 2
		if (!parameter2List || !parameter2List->isDOT())
		{
			std::cout << "Error: too few arguments given to CONS !\n";
			exit(1);
		}
		if (!parameter2List->nilRightChild())
		{
			std::cout << "Error: too many arguments given to CONS !\n";
			exit(1);
		}
		ParserTree* parameter2 = parameter2List->getChild(true);	//	parameter 2

		Value valuePara1, valuePara2;
		eval(parameter1, valuePara1, alist);
		eval(parameter2, valuePara2, alist);

		List* list = new List();
		if (valuePara1.type == LIST_VALUE)
			list->addChild(true, valuePara1.list->copy());
		else if (valuePara1.type == NUMBER_VALUE)
			list->addChild(true, valuePara1.n);
		else if (valuePara1.type == LITERAL_VALUE)
			list->addChild(true, valuePara1.str);
		else
		{
			std::cout << "Error: invalid parameters for CONS !\n";
			exit(1);
		}

		if (valuePara2.type == LIST_VALUE)
			list->addChild(false, valuePara2.list->copy());
		else if (valuePara2.type == NUMBER_VALUE)
			list->addChild(false, valuePara2.n);
		else if (valuePara2.type == LITERAL_VALUE)
			list->addChild(false, valuePara2.str);
		else
		{
			std::cout << "Error: invalid parameters for CONS !\n";
			exit(1);
		}

		value.setList(list);
	}
}

// cond
bool Semantic::condBranch(ParserTree* tree, Value& value, AList alist)
{
 	if (!tree || !tree->isDOT())
	{
		std::cout << "Error: invalid parameters for COND !\n";
		exit(1);
	}
	Value valueCondition;
    eval(tree->getChild(true), valueCondition, alist);
    if (valueCondition.type == NOTHING || valueCondition.type == FUNC_VALUE)
 	{
		std::cout << "Error: invalid parameters for COND !\n";
		exit(1);
	}
	else if (!valueCondition.isNil())
    {
        ParserTree* rightTree = tree->getChild(false);
        if (!rightTree || !rightTree->isDOT() || !rightTree->nilRightChild())
    	{
            std::cout << "Error: invalid parameters for COND !\n";
            exit(1);
        }
        eval(rightTree->getChild(true), value, alist);
        if (value.type == NOTHING || value.type == FUNC_VALUE)
        {
            std::cout << "Error: invalid parameters for COND !\n";
            exit(1);
        }
        else
        {
            return true;
        }
    }
    return false;
}

// cond
void Semantic::cond(ParserTree* tree, Value& value, AList alist)
{
	if (!tree || tree->isNIL() || !tree->isDOT())
	{
		std::cout << "Error: no branch executed for COND !\n";
		exit(1);
	}
	else
	{
		bool branchShot = condBranch(tree->getChild(true), value, alist);
        if (!branchShot)
        {
            // previous branch not executed, to the next branch
            cond(tree->getChild(false), value, alist);
        }
	}
}


bool isDistinguishedLiteralList(std::vector<std::string> literals, ParserTree* tree)
{
	if (!tree || tree->isNIL())
		return true;
	if (!tree->isDOT())
		return false;
	if (!tree->getChild(true))
		return true;

	ParserTree* literalTree = tree->getChild(true);
	if (!literalTree->isLiteral())
		return false;
	std::string str = literalTree->getAtom().str;
	if (!Util::isLiteralExcluded(str, literals))
		return false;

	literals.push_back(str);
	return isDistinguishedLiteralList(literals, tree->getChild(false));
}

// defun
void Semantic::defun(ParserTree* tree, Value& value, AList alist)
{	
	if (!tree || !tree->isDOT())
	{
		std::cout << "Error: too few arguments given to DEFUN !\n";
		exit(1);
	}
	else
	{
		ParserTree* parameter1 = tree->getChild(true);				//	parameter 1, function name
		if (!parameter1 || !parameter1->isLiteral())
		{
			std::cout << "Error: the function name given to DEFUN must be a symbol !\n";
			exit(1);
		}
		std::string funcName = parameter1->getAtom().str;
		if (!Util::isFuncNameLegal(funcName))
		{
			std::cout << "Error: the function name '" << funcName.c_str() << "' given to DEFUN is invalid !\n";
			exit(1);
		}

		ParserTree* parameter2List = tree->getChild(false);			//	list containing parameter 2 and parameter 3
		if (!parameter2List || !parameter2List->isDOT())
		{
			std::cout << "Error: too few arguments given to DEFUN !\n";
			exit(1);
		}

		ParserTree* parameter2 = parameter2List->getChild(true);	//	parameter 2, the arguments
		if (!parameter2 || !isDistinguishedLiteralList(std::vector<std::string>(), parameter2))
		{
			std::cout << "Error: function arguments given to DEFUN must be a distinguished literal list!\n";
			exit(1);
		}


		ParserTree* parameter3List = parameter2List->getChild(false);			//	list containing only one element: parameter 2
		if (!parameter3List || !parameter3List->isDOT())
		{
			std::cout << "Error: too few arguments given to DEFUN !\n";
			exit(1);
		}
		if (!parameter3List->nilRightChild())
		{
			std::cout << "Error: too many arguments given to DEFUN !\n";
			exit(1);
		}

		ParserTree* parameter3 = parameter3List->getChild(true);	//	parameter 2, the arguments
		if (!parameter3)
		{
			std::cout << "Error: no function body given to DEFUN !\n";
			exit(1);
		}

		dList.addFunction(Function(funcName, parameter2, parameter3));
		value.setFunc(funcName);
	}
}

//	evaluate values of a list
void Semantic::evalList(ParserTree* tree, Value& valueList, AList alist)
{
	List* list = new List();
	List* traverseList = list;

	if (!tree)
	{
		valueList.setList(list);
		return;
	}

	ParserTree* traverseTree = tree;

	while(true)
	{
		if (!traverseTree->isDOT())
		{
			std::cout << "Error: invalid parameters sent to the function call !\n";
			exit(1);
		}
		if (!traverseTree->getChild(true))
			break;						//	no left child, break


		Value member;
		eval(traverseTree->getChild(true), member, alist);
		
		if (member.type == LIST_VALUE)
			traverseList->addChild(true, member.list->copy());
		else if (member.type == NUMBER_VALUE)
			traverseList->addChild(true, member.n);
		else if (member.type == LITERAL_VALUE)
			traverseList->addChild(true, member.str);
		else
		{
			std::cout << "Error: invalid parameters sent to the function call !\n";
			exit(1);
		}

		traverseTree = traverseTree->getChild(false);
		if (!traverseTree || traverseTree->isNIL())
			break;
		
		else if (!traverseTree->isDOT())
		{
			std::cout << "Error: invalid parameters sent to the function call !\n";
			exit(1);
		}
		else if (!traverseTree->getChild(true))
			break;						//	no left child, break
		else
		{
			traverseList->addChild(false, new List());
			traverseList = traverseList->getChild(false);
		}
	}

	valueList.setList(list);
}

//	evaluate a call to user delcared function
void Semantic::apply(std::string funcName, Value& value, Value& valueList, AList alist)
{
	if (!dList.findFunction(funcName))
	{
		std::cout << "Error: function '" <<  funcName.c_str() << "' has not been defined !\n";
		exit(1);
	}

	List* formalList = dList.getFunctionFormal(funcName);
	List* formalListTraverse = formalList;

	List* valueListTraverse = valueList.list;

	while(true)
	{
		bool formalListEnd = (!formalListTraverse || formalListTraverse->isNIL() || (formalListTraverse->isDOT() && !formalListTraverse->getChild(true)));
		bool valueListEnd = (!valueListTraverse || valueListTraverse->isNIL() || (valueListTraverse->isDOT() && !valueListTraverse->getChild(true)));
		if (formalListEnd && valueListEnd)
			break;
		else if (formalListEnd ^ valueListEnd)
		{
			std::cout << "Error: formal and actual parameters don't match !\n";
			exit(1);
		}
		else
		{
			//	neither end
			if (!formalListTraverse->isDOT())
			{
				std::cout << "Error: invalid formal parameters for function '" << funcName.c_str() << "' !\n";
				exit(1);
			}
			else if (!valueListTraverse->isDOT())
			{
				std::cout << "Error: invalid actual parameters for function '" << funcName.c_str() << "' !\n";
				exit(1);
			}
			else
			{
				List* formalName = formalListTraverse->getChild(true);
				if (!formalName || !formalName->isLiteral())
				{
					std::cout << "Error: formal parameter should be a literal for function '" << funcName.c_str() << "' !\n";
					exit(1);
				}

				List* valueTmp = valueListTraverse->getChild(true);
				if (!valueTmp)
				{
					std::cout << "Error: invalid actual parameter for function '" << funcName.c_str() << "' !\n";
					exit(1);
				}

				Value value;
				if (valueTmp->isLiteral())
					value.setLiteral(valueTmp->getAtom().str);
				else if (valueTmp->isNumber())
					value.setNumber(valueTmp->getAtom().number);
				else
					value.setList(valueTmp->copy());
				
				alist.addVariable(Variable(formalName->getAtom().str, value));
			}
		}
		formalListTraverse = formalListTraverse->getChild(false);
		valueListTraverse = valueListTraverse->getChild(false);

	}
	eval(dList.getFunctionBody(funcName), value, alist);
}

void Semantic::printValue(ParserTree* tree, AList alist)
{
	//	Todo: if value is a list, print in list manner
	Value value;
	this->eval(tree, value, alist);
	value.print();
}



